import * as mapvgl from './mapvgl/dist/mapvgl.min.js';
import { merge, get } from 'lodash-es';
import { createGeoPoints, getGeoPointData, getPointTitle, getPointBCR } from '../CMap/mapUtils.js';

export default class BMapMarkerClusterLayer {
  constructor(map, options) {
    if (!map) {
      throw new Error('props map is required !');
    }
    this.map = map;
    this.points = [];
    this._options = Object.assign({}, options);
    this.options = this.getOptions();
    this.layer = this.getLayer();
    this.view = new mapvgl.View({ map: this.map });
    this.view.addLayer(this.layer);
    this.createLabelLayer();
    // console.log(this.layer);
  }
  getLayer() {
    return new mapvgl.ClusterLayer(this.options);
  }
  getOptions() {
    const opt = {
      uniqueKey: 'id',
      minSize: 30, // 聚合点显示的最小直径
      maxSize: 50, // 聚合点显示的最大直径
      clusterRadius: 150, // 聚合范围半径
      minPoints: 2, // 开始聚合的最少点数，点数多于此值才会被聚合
      maxZoom: 20, // 聚合的最大级别，当地图放大级别高于此值将不再聚合
      minZoom: 5, // 聚合的最小级别，当地图放大级别低于此值将不再聚合
      gradient: {
        0: 'rgba(0,159,85,0.5)',
        0.5: 'rgba(221,113,6,0.5)',
        1.0: 'rgba(170,12,12,0.5)',
      }, // 聚合点颜色梯度
      // 是否显示文字
      showText: true,
      // 设置文字样式
      textOptions: {
        fontSize: 14,
        color: '#e8e8e8',
        offset: [0, 0],
        // 格式化数字显示
        format: function (count) {
          return Number.isFinite(count) && count >= 1000 ? Math.round(count / 1000) + 'k' : count;
          // return count;
        },
      },
      labelOptions: {
        fontSize: 14,
        color: '#ffffff',
        offset: [0, -64 * 1.1],
        maxLength: 10,
      },
      // 设置非聚合的点的icon
      iconOptions: {
        icon: 'images/marker.png',
        scale: 1,
        width: 46,
        height: 64,
        offset: [0, -32],
      },
      enablePicked: true,
    };
    return merge({}, opt, this._options, { onClick: (e) => this.handleClick(e) });
  }
  createLabelLayer() {
    let _this = this;
    let labelOptions = Object.assign({}, this.options.labelOptions);
    if (this.layer && this.layer.iconLayer && labelOptions.visible !== false) {
      this.labelLayer = new mapvgl.TextLayer(labelOptions);
      this.view.addLayer(this.labelLayer);
      this.layer.iconLayer.onLayerChanged = this.layer.iconLayer.onChanged;
      this.layer.iconLayer.onChanged = function (options, list) {
        if (!Array.isArray(list)) list = [];
        let labelList = list.map((item) => {
          let data = get(item, 'properties.originData');
          let text = getPointTitle(data);
          let color = labelOptions.color;
          if (typeof labelOptions.format === 'function') {
            text = labelOptions.format(text);
          }
          if (typeof text === 'string' && text.length > labelOptions.maxLength) {
            text = text.substring(0, labelOptions.maxLength) + '...';
          }
          let { offset } = getPointBCR(data, {
            width: _this.options.iconOptions.width,
            height: _this.options.iconOptions.height,
            offset: labelOptions.offset,
            anchor: 'topLabel',
          });
          return merge({}, item, { properties: { text, color, offset } });
        });
        _this.labelLayer.clear();
        _this.labelLayer.setData(labelList);
        _this.layer.iconLayer.onLayerChanged(options, list);
      };
    }
  }
  handleClick(e) {
    if (e.dataItem) {
      // 可通过dataItem下面的children属性拿到被聚合的所有点
      const data = getGeoPointData(e.dataItem);
      // console.log(data);
      if (data) {
        if (typeof data.onClick === 'function') {
          data.onClick(data);
        } else if (typeof this._options.onClick === 'function') {
          this._options.onClick(data);
        } else if (typeof this.onClick === 'function') {
          this.onClick(data);
        }
      }
    }
  }
  onClick(data) {
    console.log(data);
  }
  isVisible(data) {
    return !!data;
  }
  getLayerVisible() {
    return this.view._visible;
  }
  setData(list) {
    this.points = createGeoPoints(list, {
      width: this.options.iconOptions.width,
      height: this.options.iconOptions.height,
      offset: this.options.iconOptions.offset,
      getTitle: this.options.getTitle,
    });
    this.filter();
  }
  getData(predicate) {
    if (typeof predicate !== 'function') {
      predicate = this.isVisible;
    }
    if (this.getLayerVisible() !== true) {
      return [];
    }
    return this.points.reduce((res, item) => {
      const data = getGeoPointData(item);
      if (predicate(data)) res.push(data);
      return res;
    }, []);
  }
  getPoints(predicate) {
    if (typeof predicate !== 'function') {
      predicate = this.isVisible;
    }
    if (this.getLayerVisible() !== true) {
      return [];
    }
    return this.points.filter((item) => {
      return predicate(getGeoPointData(item));
    });
  }
  filter(predicate) {
    if (typeof predicate !== 'function') {
      predicate = this.isVisible;
    }
    const data = this.getPoints(predicate);
    this.layer.clear();
    this.layer.setData(data);
  }
  toggle(visible) {
    let isVisible = this.getLayerVisible();
    if (isVisible !== visible) {
      this.view[visible === true ? 'show' : 'hide']();
    }
  }
  clear() {
    if (this.labelLayer) {
      this.labelLayer.clear();
    }
    this.layer.clear();
  }
  destroy() {
    if (this.labelLayer) {
      this.labelLayer.destroy();
    }
    this.layer.destroy();
    this.view.destroy();
  }
}
